package titan.wizards.newTitanProject;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.Date;
import java.util.Random;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchWizard;
import titan.messages.Messages;
import titan.utils.ContentModifier;
import titan.utils.FileUtils;
import titan.utils.TitanUtils;

/**
 * This wizard allows the creation of a Titan application
 * and the association of this application to a Eclipse project. The wizard is composed of three steps:
 * project location configuration, general Titan application configuration and database configuration.
 */
public class TitanWizard extends Wizard implements INewWizard {
	LocalPage localPage;
	ProjectPage projectPage;
	DataBasePage dataBasePage;
	boolean status;

	/**
	 * Constructor for TitanWizard.
	 */
	public TitanWizard() {
		super();
		setNeedsProgressMonitor(true);
		status = false;
	}

	/**
	 * {@inheritDoc}
	 */
	public void addPages() {
		localPage = new LocalPage();
		addPage(localPage);
		projectPage = new ProjectPage();
		addPage(projectPage);
		dataBasePage = new DataBasePage();
		addPage(dataBasePage);
	}

	/**
	 * This method is called when 'Finish' button is pressed in the wizard. It
	 * will create an operation and run it using wizard as execution context.
	 * @return true if all went OK and false otherwise
	 */
	public boolean performFinish() {
		IRunnableWithProgress op = new IRunnableWithProgress() {
			public void run(IProgressMonitor monitor)
					throws InvocationTargetException {
				try {
					doFinish();
				} catch (CoreException e) {
					throw new InvocationTargetException(e);
				} finally {
					monitor.done();
				}
			}
		};
		try {
			getContainer().run(true, false, op);
		} catch (InterruptedException e) {
			return false;
		} catch (InvocationTargetException e) {
			Throwable realException = e.getTargetException();
			MessageDialog.openError(getShell(), Messages.Error, realException.getMessage());
			return false;
		}
		return status;
	}

	/**
	 * Do the finish action. It will create the Titan Project and import it to Eclipse
	 * @throws CoreException if an Eclipse core exception occurred
	 */
	private void doFinish() throws CoreException {
		getShell().getDisplay().syncExec( new Runnable() {  public void run() {
			try {
				status = false;

	            String projectDir = localPage.projectPath.getText();
				if (!projectDir.endsWith(File.separator))
					projectDir += File.separator;

				//check if exist an Eclipse project with the same name
				TitanUtils tu = new TitanUtils(projectDir);
				tu.setProjectName(projectPage.name.getText());
				if(tu.existEclipseProject())
					if(!MessageDialog.openQuestion(getShell(), Messages.Error, Messages.ProjTakenCotinue))
						return;
				//Get the path to template resource directory
				File src = FileUtils.getResourceFile("/resources/template"); //$NON-NLS-1$
				File dest = new File(projectDir);
				//Copy the files from template directory to project directory
				FileUtils.copyAllFiles(src,dest);

				//Copy db.sql file to project directory
				File sql = TitanUtils.getDbSql(dataBasePage.schema.getText());
				FileUtils.copyFile(sql, new File(projectDir+"db.sql")); //$NON-NLS-1$

				//Copy Logo File to image's project directory
				File sourceLogo = new File(projectPage.logoPath.getText());
	            File imageDir = new File(projectDir+"image"); //$NON-NLS-1$
	            File destineLogo = new File(projectDir+"image"+File.separator+sourceLogo.getName()); //$NON-NLS-1$
				if (!imageDir.exists())
					imageDir.mkdir();
				if(projectPage.logoPath.getText().compareTo("image"+File.separator+"titan.jpg") != 0) //$NON-NLS-1$
					FileUtils.copyFile(sourceLogo, destineLogo);
				else
					sourceLogo = destineLogo;

				//Start editing Xmls with Titan Wizard data
				ContentModifier xml = new ContentModifier();

				//Get languages list string
				String language = ""; //$NON-NLS-1$
				for (int i = 0; i < projectPage.usedLang.getItemCount(); i++)
		            if(i == 0)
		                language = projectPage.usedLang.getItem(i);
		            else
		               language += ", " + projectPage.usedLang.getItem(i); //$NON-NLS-1$

				//Get random MD5 hash instance
	            MessageDigest digest = java.security.MessageDigest.getInstance("MD5"); //$NON-NLS-1$
	            digest.update(new Date().toString().getBytes());
	            Random r = new Random();
	            byte[] bytes;

	            //read and store original xml content and variables to modify
	            String[] variables = {"allSectionsTitan","cachePathTitan", "corePathTitan", "debugModeTitan", "descTitan", "emailTitan", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
						"languageTitan", "loginUrlTitan", "nameTitan","onlyFirefoxTitan", "reposPathTitan", "sessionHashTitan", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
						"timezoneTitan", "urlTitan", "useChatTitan", "hostTitan", "databaseNameTitan", "passwordTitan", "portTitan",  //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
						"schemaTitan", "PostgreSQLTitan", "userTitan", "securityHashTitan", "searchHashTitan", "logoTitan"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
	            String titanXml = projectDir + "configure" + File.separator + "titan.xml"; //$NON-NLS-1$ //$NON-NLS-2$
				xml.readContent(titanXml, variables, false);

				//insert Titan Wizard data into final xml content
				xml.modifyContent(new Boolean(projectPage.section.getSelection()).toString());
				String cache = projectPage.cacheDir.getText();
				xml.modifyContent(cache.endsWith(File.separator)? cache : cache + File.separator);
				String core = localPage.coreLocation.getText();
				xml.modifyContent(core.endsWith(File.separator)? core : core + File.separator);
				xml.modifyContent(new Boolean(projectPage.debug.getSelection()).toString());
				xml.modifyContent(projectPage.description.getText());
				xml.modifyContent(projectPage.email.getText());
				xml.modifyContent(language);
				xml.modifyContent(projectPage.loginUrl.getText());
				xml.modifyContent(projectPage.name.getText());
				xml.modifyContent(new Boolean(projectPage.firefox.getSelection()).toString());
				String repos = localPage.reposLocation.getText();
				xml.modifyContent(repos.endsWith(File.separator)? repos : repos + File.separator);
				bytes = digest.digest(Long.toString(Math.abs(r.nextLong()), 36).getBytes()); //generate random MD5 hash string
	            xml.modifyContent(String.format("%1$032X", new BigInteger(1, bytes))); //$NON-NLS-1$
	            String time = projectPage.timeZoneCombo.getItem(projectPage.timeZoneCombo.getSelectionIndex());
	            time = time.substring(time.lastIndexOf('-')+2);
	            xml.modifyContent(time);
				xml.modifyContent(projectPage.url.getText());
				xml.modifyContent(new Boolean(projectPage.chat.getSelection()).toString());
				xml.modifyContent(dataBasePage.host.getText());
				xml.modifyContent(dataBasePage.name.getText());
				xml.modifyContent(dataBasePage.password.getText());
				xml.modifyContent(dataBasePage.port.getText());
				xml.modifyContent(dataBasePage.schema.getText());
				xml.modifyContent(dataBasePage.sgbd.getText());
				xml.modifyContent(dataBasePage.user.getText());
				bytes = digest.digest(Long.toString(Math.abs(r.nextLong()), 36).getBytes());
	            xml.modifyContent(String.format("%1$032X", new BigInteger(1, bytes))); //$NON-NLS-1$
				bytes = digest.digest(Long.toString(Math.abs(r.nextLong()), 36).getBytes());
	            xml.modifyContent(String.format("%1$032X", new BigInteger(1, bytes))); //$NON-NLS-1$
				xml.modifyContent(sourceLogo.getName());

	            //write final xml content into the file read
				xml.writeContent();
				

				//Import project to Eclipse
				tu.setCorePath(localPage.coreLocation.getText());
				tu.setReposPath(localPage.reposLocation.getText());
				tu.importProject();
				status = true;
			} catch (Exception e) {
				MessageDialog.openError(getShell(), Messages.Error,e.getMessage());
			}
		}});
	}

	/**
	 * @see IWorkbenchWizard#init(IWorkbench, IStructuredSelection)
	 */
	public void init(IWorkbench workbench, IStructuredSelection selection) {
		//do nothing
	}

	/**
	 * {@inheritDoc}
	 */
	public boolean canFinish() {
		if(dataBasePage.canFinish() && localPage.canFlipToNextPage() && projectPage.canFlipToNextPage())
			return true;
		return false;
	}

	/**
	 * {@inheritDoc}
	 */
	public String getWindowTitle() {
		return new String(Messages.NewTitanProject);
	}
}